/*
 * EasyCamera
 *
 * Copyright (c) 2020.  Frezrik frezrik@126.com
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package com.camera.widget;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;

import java.util.Arrays;

public class YuvSurfaceView
        extends GLSurfaceView
{
    /** Yuv的图像渲染器 */
    private YuvRenderer mRenderer;
    private double mRequestedAspect = -1.0;
    private int mSize;
    private byte[] U;
    private byte[] V;

    public YuvSurfaceView(Context context) {
        this(context, null);
    }

    public YuvSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    /** 初始化 */
    private void init(){
        // 创建一个OpenGL ES 2.0 context，将要使用2.0版的API
        setEGLContextClientVersion(2);
        // 创建一个渲染器
        mRenderer = new YuvRenderer();
        // 设置渲染器
        setRenderer(mRenderer);
        // 设置渲染模式
        // GLSurfaceView.RENDERMODE_CONTINUOUSLY：持续型模式，以一定周期定时重新绘制view
        // GLSurfaceView.RENDERMODE_WHEN_DIRTY：通知型模式，只有在绘制数据改变时才绘制view
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mRenderer != null)
            mRenderer.release();
    }

    /*@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mRequestedAspect > 0) {
            int initialWidth = MeasureSpec.getSize(widthMeasureSpec);
            int initialHeight = MeasureSpec.getSize(heightMeasureSpec);

            final int horizPadding = getPaddingLeft() + getPaddingRight();
            final int vertPadding = getPaddingTop() + getPaddingBottom();
            initialWidth -= horizPadding;
            initialHeight -= vertPadding;

            final double viewAspectRatio = (double) initialWidth / initialHeight;
            final double aspectDiff = mRequestedAspect / viewAspectRatio - 1;

            if (mRequestedAspect < 1 && viewAspectRatio < 1) {
                initialWidth *= 0.6;
            }

            if (Math.abs(aspectDiff) > 0.01) {
                if (aspectDiff > 0) {
                    // width priority decision
                    initialHeight = (int) (initialWidth / mRequestedAspect);
                } else {
                    // height priority decision
                    initialWidth = (int) (initialHeight * mRequestedAspect);
                }

                initialWidth += horizPadding;
                initialHeight += vertPadding;

                widthMeasureSpec = MeasureSpec.makeMeasureSpec(initialWidth, MeasureSpec.EXACTLY);
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(initialHeight, MeasureSpec.EXACTLY);

            }
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
*/
    /**
     * 设置宽高比
     * @param aspectRatio
     */
    public void setAspectRatio(final double aspectRatio) {
        if (aspectRatio < 0) {
            throw new IllegalArgumentException();
        }
        if (mRequestedAspect != aspectRatio) {
            mRequestedAspect = aspectRatio;
            requestLayout();
        }
    }

    public void setResolution(int nWidth, int nHeight) {
        if (mRenderer != null) {
            mSize = nWidth * nHeight;
            U = new byte[mSize / 4];
            V = new byte[mSize / 4];
            mRenderer.setResolution(nWidth, nHeight);
        }
    }

    public void setDisplayOrientation(int degrees, boolean needMirror) {
        if (mRenderer != null)
            mRenderer.setDisplayOrientation(degrees, needMirror);
    }

    public void setYUV420spData(byte[] yuv420p) { // YYYY UVUV
        synchronized (this) {
            if (mRenderer != null && yuv420p != null) {
                for (int i = mSize; i < mSize * 3 / 2; i += 2) {
                    U[(i - mSize) / 2] = yuv420p[i];
                    V[(i - mSize) / 2] = yuv420p[i + 1];
                }

                mRenderer.setYUVRenderData(
                    Arrays.copyOfRange(yuv420p, 0, mSize),
                    U,
                    V);
                requestRender();
            }
        }
    }

    public void setNV21Data(byte[] nv21Data) { // YYYY VUVU
        synchronized (this) {
            if (mRenderer != null && nv21Data != null) {
                for (int i = mSize; i < mSize * 3 / 2; i += 2) {
                    U[(i - mSize) / 2] = nv21Data[i];
                    V[(i - mSize) / 2] = nv21Data[i + 1];
                }

                mRenderer.setYUVRenderData(
                        Arrays.copyOfRange(nv21Data, 0, mSize),
                        V,
                        U);
                requestRender();
            }
        }
    }

    public void setYUV420pData(byte[] yuv420p) { // YYYYYYYY UUVV
        synchronized (this) {
            if (mRenderer != null && yuv420p != null) {


                mRenderer.setYUVRenderData(
                        Arrays.copyOfRange(yuv420p, 0, mSize),
                        Arrays.copyOfRange(yuv420p, mSize, mSize + mSize / 4),
                        Arrays.copyOfRange(yuv420p, mSize * 5 / 4, mSize * 5 / 4 + mSize / 4));
                requestRender();
            }
        }
    }

    public void clear() {
        if (mRenderer != null) {
            mRenderer.clear(this);
        }
    }

}
